<script setup lang="ts">
import type { FieldRule, FormInstance } from '@arco-design/web-vue'
import type { ComputedRef } from 'vue'

import type { IMatchConfig, Operator, RuleValue } from '../types'
import { getFieldConfig } from '../utils'

interface IEmit {
  (event: 'update:field', value: string): void
  (event: 'update:operator', value: Operator): void
  (event: 'update:value', value: RuleValue): void
  (event: 'update:custom-field', value: RuleValue): void
  (event: 'add'): void
  (event: 'delete'): void
}

interface IProps {
  disableDelete?: boolean
  disableAdd?: boolean
  disabledAll?: boolean
  field: string
  operator: Operator
  value: string | number | string[] | number[]
  customField?: string
}
const props = withDefaults(defineProps<IProps>(), {
  disableDelete: false,
  disableAdd: false,
  disabledAll: false,
})
const emit = defineEmits<IEmit>()
/**
 * 字段配置列表
 */
const matchConfig = inject('matchConfig') as ComputedRef<IMatchConfig[]>
const formRef = ref<FormInstance>()
const formData = reactive<any>({
  fieldType: '',
  customParam: '',
  operator: '',
  modelValue: '',
})
const formRules = computed<{ [key: string]: FieldRule[] }>(() => {
  return {
    fieldType: [{ required: true, message: '请选择匹配字段', trigger: 'blur' }],
    operator: [{ required: true, message: '请选择运算符', trigger: 'blur' }],
    customParam: [
      { required: true, message: '请输入自定义参数', trigger: 'blur' },
    ],
  }
})
/**
 * 当前所选择的字段配置项
 */
const fieldOption = computed(() => {
  return getFieldConfig(formData.fieldType, matchConfig.value)
})
const getValueData = computed(() => {
  return fieldOption?.value?.operatorOptions!.find(
    (item: any) => item.value === formData.operator,
  )
})
/**
 * 是否可以多选
 */
const multiple = computed(() => getValueData.value?.count > 1)

// 数字格式校验
function validateNumber(
  value: string | number | (string | number)[],
  callback,
) {
  const reg = /^-?\d+$/
  if (multiple.value) {
    const list = (value as string[]).filter(Boolean)
    for (const item of list) {
      if (!reg.test(String(item)))
        return callback('请输入数字')
    }
  } else {
    if (!reg.test(String(value)))
      callback('请输入数字')
  }
}
// 数字大小校验
function validateNumberSize(
  value: string | number | (string | number)[],
  callback,
) {
  function condition(val?: string | number) {
    return (
      Number(val) < getValueData.value?.min
      || Number(val) > getValueData.value?.max
    )
  }
  if (multiple.value) {
    const list = (value as string[]).filter(Boolean)
    if (list.length <= getValueData.value?.count) {
      for (const item of list) {
        if (condition(item)) {
          return callback(
            `请输入${getValueData.value?.min}-${getValueData.value?.max}的整数`,
          )
        }
        callback()
      }
    } else {
      callback(getValueData.value?.example)
    }
  } else {
    if (condition(String(value)))
      callback(getValueData.value?.example)
    callback()
  }
}
// 字符长度校验
function validateStrSize(value: string | string[], callback) {
  function condition(val?: string | number) {
    return (
      String(val).length < getValueData.value?.min
      || String(val).length > getValueData.value?.max
    )
  }
  if (multiple.value) {
    const list = (value as string[]).filter(Boolean)
    if (list.length <= getValueData.value?.count) {
      for (const item of list) {
        if (condition(item)) {
          return callback(
            `请输入${getValueData.value?.min}-${getValueData.value?.max}个字符`,
          )
        }
        callback()
      }
    } else {
      callback(getValueData.value?.example)
    }
  } else {
    if (condition(value)) {
      callback(
        `请输入${getValueData.value?.min}-${getValueData.value?.max}个字符`,
      )
    }
    callback()
  }
}
const secondExample = computed(() => {
  const data = {} as any
  fieldOption.value?.operatorOptions.forEach((item) => {
    data[item.value] = item.example
  })
  return data
})
const getExample = computed(() => {
  return secondExample.value[formData.operator]
})

/**
  是否是自定义参数
 */
const isCustom = computed(() => {
  return fieldOption.value?.needCustomField
})
/**
  是否是具有二层options的select
 */
const isSecondOptions = computed(
  () => getValueData.value?.allowed_values.length,
)
// formData
const modelValueRules = ref<FieldRule[]>([])
watchEffect(() => {
  const noValid
    = ((!fieldOption.value?.field.type || !fieldOption.value.field.validator)
      && !formData.operator)
    || (formData.fieldType
      && formData.operator
      && getValueData.value?.count === 0
      && !formData.modelValue)
  if (noValid) {
    modelValueRules.value = [{ required: false }]
  } else if (!formData.modelValue) {
    modelValueRules.value = [{ required: true, message: '字段必填' }]
  } else if (fieldOption.value?.field.type === 'input') {
    if (getValueData.value?.type === 'int') {
      modelValueRules.value?.push({ required: true, validator: validateNumber })
      modelValueRules.value?.push({ validator: validateNumberSize })
    } else {
      modelValueRules.value?.push({
        required: true,
        validator: validateStrSize,
      })
    }
  }
})

/**
 * 针对动态select options
 */
const valueOptions = ref<LabelValue<string | number>[]>([])
watchEffect(async () => {
  if (!fieldOption.value) {
    return
  }
  if (typeof fieldOption.value.field.options === 'function') {
    valueOptions.value = await fieldOption.value.field.options()
  } else {
    valueOptions.value = fieldOption.value.valueOptions.length
      ? fieldOption.value.valueOptions
      : fieldOption.value.field.options!
  }
})
watchEffect(() => {
  formData.fieldType = formData.fieldType
    ? formData.fieldType
    : matchConfig.value[0].value
  formData.operator = formData.operator
    ? formData.operator
    : matchConfig.value[0].operatorOptions[0].value
})

// watch(
//   formData,formData
//   async (v) => {
//     await nextTick()
//     console.log(v)
//     if (!fieldOption.value) {
//       return
//     }
//     formData.modelValue = ''
//     formData.operator = matchConfig.value[0].operatorOptions[0].value
//   },
//   {
//     deep: true
//   }
// )
function handleFieldChange(val: string) {
  // const firstField = fieldOption.value?.field?.options[0]?.field ?? ''
  const operator = matchConfig.value[0].operatorOptions[0].value
  formData.modelValue = ''
  formData.customParam = ''
  formData.operator = operator
  emit('update:field', val)
  emit('update:value', formData.modelValue)
}

function handleOperatorChange(op: any) {
  let value: any
  // const firstField = fieldOption.value?.field?.options[0]?.field
  if (getValueData.value?.allowed_values.length && !formData.modelValue) {
    value = formData.modelValue
      ? formData.modelValue
      : getValueData.value?.allowed_values[0].field
  } else {
    value = ''
  }
  if (
    getValueData.value?.count === 1
    && fieldOption.value?.field.options?.length
  ) {
    value = fieldOption.value?.field.options[0].field
  }
  // if (getValueData.value?.count > 1) {
  //   if (Array.isArray(formData.modelValue)) {
  //     value = firstField
  //   } else {
  //     value = firstField
  //   }
  // }
  formData.operator = op
  formData.modelValue = value
  emit('update:operator', op)
  emit('update:value', value)
}
watch(
  () => [
    formData.fieldType,
    formData.operator,
    formData.modelValue,
    formData.customParam,
  ],
  () => {
    setTimeout(formRef.value!.clearValidate()!)
  },
  {
    deep: true,
  },
)
function setValue() {
  emit('update:field', formData.fieldType)
  emit('update:operator', formData.operator)
  emit('update:value', formData.modelValue)
  emit('update:custom-field', formData.customParam)
}
async function validate() {
  setValue()
  return await formRef.value?.validate()
}
defineExpose({
  validate,
})
onMounted(() => {
  formData.fieldType = props.field
  formData.operator = props.operator
  formData.modelValue = props.value
  formData.customParam = props.customField
  setValue()
})
</script>

<template>
  <a-form
    ref="formRef"
    :model="formData"
    :rules="formRules"
    inline
    class="matching-rule"
  >
    <section class="flex items-start gap-x-1">
      <!-- 字段 -->
      <a-form-item
        field="fieldType"
        hide-asterisk
        hide-label
        class="!mb-0"
      >
        <a-select
          v-model="formData.fieldType"
          class="option-height"
          :class="isCustom ? '!w-[168px]' : '!w-[340px]'"
          placeholder="请选择"
          :disabled="disabledAll"
          @change="handleFieldChange"
        >
          <a-option
            v-for="item in matchConfig"
            :key="item.value"
            class="h-[28px]"
            :label="item.label"
            :value="item.value"
          />
        </a-select>
      </a-form-item>
      <!-- 自定义参数 -->
      <a-form-item
        v-if="isCustom"
        field="customParam"
        hide-asterisk
        hide-label
        class="!mb-0"
      >
        <a-input
          v-model="formData.customParam"
          :disabled="disabledAll"
          class="!w-[168px]"
          :title="fieldOption?.customFieldExample"
          :placeholder="fieldOption?.customFieldExample"
        />
      </a-form-item>
    </section>
    <!-- 运算符 -->
    <a-form-item
      field="operator"
      hide-asterisk
      hide-label
      class="!mb-0"
    >
      <a-select
        v-model="formData.operator"
        :disabled="
          !fieldOption
            || fieldOption?.field.valueType === 'boolean'
            || disabledAll
        "
        placeholder="请选择"
        class="!w-[128px]"
        @change="handleOperatorChange"
      >
        <a-option
          v-for="item in fieldOption?.operatorOptions"
          :key="item.value"
          class="h-[28px]"
          :label="item.label"
          :value="item.value"
        />
      </a-select>
    </a-form-item>
    <!-- 值 -->

    <a-form-item
      :rules="modelValueRules"
      class="min-w-[200px] flex-1 !mb-0"
      field="modelValue"
      hide-asterisk
      hide-label
    >
      <div
        v-if="getValueData?.count !== 0"
        class="h-full w-full flex items-center"
      >
        <template
          v-if="fieldOption?.field.type === 'select' || isSecondOptions"
        >
          <!-- 单独判断multiple，用两个select是因为placeholder在动态切换multiple后有不显示的bug -->
          <template v-if="multiple">
            <a-select
              v-model="formData.modelValue"
              :multiple="true"
              size="mini"
              :limit="getValueData?.count"
              :disabled="!fieldOption || !formData.operator || disabledAll"
              :placeholder="
                getExample
                  ? getExample
                  : fieldOption
                    ? fieldOption?.field.placeholder
                    : '请选择匹配字段'
              "
              allow-search
              class="multi_select !min-h-8"
            >
              <a-option
                v-for="item in valueOptions"
                :key="item.field"
                class="h-[28px]"
                :label="item.show_name"
                :value="item.field"
              />
            </a-select>
          </template>
          <template v-else>
            <a-select
              v-model="formData.modelValue"
              :disabled="!fieldOption || !formData.operator || disabledAll"
              :placeholder="
                getExample
                  ? getExample
                  : fieldOption
                    ? fieldOption?.field.placeholder
                    : '请选择匹配字段'
              "
              allow-search
            >
              <a-option
                v-for="item in valueOptions"
                :key="item.field"
                class="h-[28px]"
                :label="item.show_name"
                :value="item.field"
              />
            </a-select>
          </template>
        </template>
        <template v-else-if="fieldOption?.field.type === 'input'">
          <section
            v-if="!multiple"
            class="w-full"
          >
            <a-input
              v-model="formData.modelValue"
              :disabled="!fieldOption || !formData.operator || disabledAll"
              :max-length="getValueData?.max"
              :title="
                getExample
                  ? getExample
                  : fieldOption
                    ? fieldOption?.field.placeholder
                    : '请选择匹配字段'
              "
              :placeholder="
                getExample
                  ? getExample
                  : fieldOption
                    ? fieldOption?.field.placeholder
                    : '请选择匹配字段'
              "
            />
          </section>
          <a-select
            v-else
            v-model="formData.modelValue"
            :disabled="!fieldOption || !formData.operator || disabledAll"
            :placeholder="
              getExample ? getExample : fieldOption?.field.placeholder
            "
            no-data-text="请输入并选择"
            allow-search
            allow-create
            multiple
            default-first-option
            class="multi_select !min-h-8"
          />
        </template>

        <template v-else-if="fieldOption?.field.type === 'switch'">
          <a-switch
            :model-value="formData.modelValue"
            :disabled="disabledAll"
            @update:model-value="(val: any) => (formData.modelValue = val)"
          />
        </template>

        <template v-else>
          <span class="text-xs text-[#86909C]">请先选择匹配字段</span>
        </template>
      </div>
    </a-form-item>

    <div class="action h-8 w-8 flex items-center justify-center">
      <!--
      <a-button
      v-if="!disableAdd"
      :disabled="disabledAll"

      class="mr-2 w-[30px]"
      @click="emit('add')">
      <i-icons-table-add />
    </a-button>
      -->
      <a-link
        :disabled="disableDelete || disabledAll"
        status="danger"
        :hoverable="false"
        class="flex items-center"
        long
        @click="emit('delete')"
      >
        <i-icons-delete />
      </a-link>
    </div>
  </a-form>
</template>

<style scoped lang="less">
:deep(.multi_select) {
  padding: 2px 12px;
  min-height: 32px;
  background-color: #fff;

  // .arco-select-view-inner {
  //   white-space: nowrap;
  // padding-top: 3px !important;

  .arco-tag {
    background: #f2f3f5;
    margin: 3px;
  }

  //   .arco-select-view-input {
  //     width: 64px !important;
  //     height: 20px !important;
  //   }

  //   .arco-select-view-input::placeholder {
  //     color: #86909c;
  //     font-size: 12px;
  //   }
  // }
}
</style>
